aboutsummaryrefslogtreecommitdiff
path: root/src/routes/user/[user]/+page.svelte
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-10-09 00:41:20 -0700
committerFuwn <[email protected]>2024-10-09 00:41:43 -0700
commit998b63a35256ac985a5a2714dd1ca451af4dfd8a (patch)
tree50796121a9d5ab0330fdc5d7e098bda2860d9726 /src/routes/user/[user]/+page.svelte
parentfeat(graphql): add badgeCount field (diff)
downloaddue.moe-998b63a35256ac985a5a2714dd1ca451af4dfd8a.tar.xz
due.moe-998b63a35256ac985a5a2714dd1ca451af4dfd8a.zip
chore(prettier): use spaces instead of tabs
Diffstat (limited to 'src/routes/user/[user]/+page.svelte')
-rw-r--r--src/routes/user/[user]/+page.svelte1076
1 files changed, 538 insertions, 538 deletions
diff --git a/src/routes/user/[user]/+page.svelte b/src/routes/user/[user]/+page.svelte
index 84f121ea..d60ea8e5 100644
--- a/src/routes/user/[user]/+page.svelte
+++ b/src/routes/user/[user]/+page.svelte
@@ -1,550 +1,550 @@
<script lang="ts">
- import settings from '$stores/settings';
- import ParallaxImage from '../../../lib/Image/ParallaxImage.svelte';
- import { typeSchedule, type ParseResult } from '$lib/Hololive/hololive';
- import HeadTitle from '$lib/Home/HeadTitle.svelte';
- import Message from '$lib/Loading/Message.svelte';
- import { estimatedDayReading } from '$lib/Media/Manga/time';
- import Skeleton from '$lib/Loading/Skeleton.svelte';
- import root from '$lib/Utility/root';
- import locale from '$stores/locale';
- import { onMount } from 'svelte';
- import authorisedUsers from '$lib/Data/Static/authorised.json';
- import tooltip from '$lib/Tooltip/tooltip';
- import AnimeRateLimited from '$lib/Error/AnimeRateLimited.svelte';
- import identity from '$stores/identity';
- import SettingHint from '$lib/Settings/SettingHint.svelte';
- import proxy from '$lib/Utility/proxy';
- import { parseScheduleHtml } from '$lib/Data/hololive';
- import type { Preferences } from '../../../graphql/$types';
- import SvelteMarkdown from 'svelte-markdown';
- import MarkdownLink from '$lib/MarkdownLink.svelte';
- import LinkedTooltip from '$lib/Tooltip/LinkedTooltip.svelte';
- import { graphql } from '$houdini';
-
- export let data;
-
- $: ({ Profile } = data);
- $: preferences = $Profile.fetching ? undefined : ($Profile.data?.User.preferences as Preferences);
-
- const setCategoriesQuery = graphql(`
- mutation SetCategories($categories: [String!]!) {
- setPinnedBadgeWallCategories(categories: $categories) {
- id
-
- preferences {
- pinned_badge_wall_categories
- }
- }
- }
- `);
-
- const toggleCategoryQuery = graphql(`
- mutation ToggleCategory($category: String!) {
- togglePinnedBadgeWallCategory(category: $category) {
- id
-
- preferences {
- pinned_badge_wall_categories
- }
- }
- }
- `);
-
- const toggleHideMissingBadgesQuery = graphql(`
- mutation ToggleHideMissingBadges {
- toggleHideMissingBadges {
- id
-
- preferences {
- hide_missing_badges
- }
- }
- }
- `);
-
- const toggleHideAWCBadgesQuery = graphql(`
- mutation ToggleHideAWCBadges {
- toggleHideAWCBadges {
- id
-
- preferences {
- hide_awc_badges
- }
- }
- }
- `);
-
- const setBiographyQuery = graphql(`
- mutation SetBiography($biography: String!) {
- setBiography(biography: $biography) {
- id
-
- preferences {
- biography
- }
- }
- }
- `);
-
- const setBadgeWallCSSQuery = graphql(`
- mutation SetBadgeWallCSS($css: String!) {
- setBadgeWallCSS(css: $css) {
- id
-
- preferences {
- badge_wall_css
- }
- }
- }
- `);
-
- $: userData = data.userData;
-
- let error = false;
- let schedule: ParseResult | undefined = undefined;
- let draggedCategory: string | null = null;
- let draggedOverCategory: string | null = null;
-
- $: displayBadges = (username: string, badges: number | string) =>
- $locale({
- values: {
- badges: badges,
- username
- }
- }).user.profile.badges;
-
- const handleDragStart = (
- event: DragEvent & { currentTarget: EventTarget & HTMLDivElement },
- category: string | null
- ) => {
- draggedCategory = category;
-
- if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move';
- };
-
- const handleDragOver = (event: any) => {
- event.preventDefault();
-
- event.dataTransfer.dropEffect = 'move';
- };
-
- const handleDragEnter = (
- event: DragEvent & { currentTarget: EventTarget & HTMLDivElement },
- category: string | null
- ) => {
- event.preventDefault();
-
- if (draggedCategory !== category && preferences && draggedCategory) {
- draggedOverCategory = category;
-
- const categories = preferences.pinned_badge_wall_categories;
- const draggedIndex = categories.indexOf(draggedCategory);
- const targetIndex = categories.indexOf(category || '');
-
- categories.splice(draggedIndex, 1);
- categories.splice(targetIndex, 0, draggedCategory);
-
- preferences.pinned_badge_wall_categories = categories;
- }
- };
-
- const handleDragLeave = (
- event: DragEvent & { currentTarget: EventTarget & HTMLDivElement },
- category: string
- ) => {
- event.preventDefault();
-
- if (draggedOverCategory === category && preferences && draggedCategory) {
- draggedOverCategory = null;
-
- const categories = preferences.pinned_badge_wall_categories;
- const draggedIndex = categories.indexOf(draggedCategory);
-
- categories.splice(draggedIndex, 1);
- categories.splice(categories.indexOf(category) + 1, 0, draggedCategory);
-
- preferences.pinned_badge_wall_categories = categories;
- }
- };
-
- const handleDrop = (event: { preventDefault: () => void }) => {
- event.preventDefault();
-
- if (userData && preferences)
- setCategoriesQuery
- .mutate({
- categories: preferences.pinned_badge_wall_categories
- })
- .then();
-
- draggedCategory = null;
- draggedOverCategory = null;
- };
-
- onMount(async () => {
- schedule = typeSchedule(
- parseScheduleHtml(
- await (
- await fetch(proxy('https://schedule.hololive.tv'), {
- headers: {
- Cookie: 'timezone=Asia/Tokyo'
- }
- })
- ).text()
- )
- );
- });
-
- const getBadgeWallCSS = () =>
- (document.getElementById('badgeWallCSS') as HTMLTextAreaElement).value;
-
- const getBiography = () =>
- (document.getElementById('biography') as HTMLTextAreaElement).value.slice(0, 3000);
-
- const toggleCategory = () => {
- if (!userData) return;
-
- const categoryElement = document.getElementById('category') as HTMLInputElement;
- const category = categoryElement.value;
-
- toggleCategoryQuery.mutate({ category }).then();
-
- categoryElement.value = '';
- };
+ import settings from '$stores/settings';
+ import ParallaxImage from '../../../lib/Image/ParallaxImage.svelte';
+ import { typeSchedule, type ParseResult } from '$lib/Hololive/hololive';
+ import HeadTitle from '$lib/Home/HeadTitle.svelte';
+ import Message from '$lib/Loading/Message.svelte';
+ import { estimatedDayReading } from '$lib/Media/Manga/time';
+ import Skeleton from '$lib/Loading/Skeleton.svelte';
+ import root from '$lib/Utility/root';
+ import locale from '$stores/locale';
+ import { onMount } from 'svelte';
+ import authorisedUsers from '$lib/Data/Static/authorised.json';
+ import tooltip from '$lib/Tooltip/tooltip';
+ import AnimeRateLimited from '$lib/Error/AnimeRateLimited.svelte';
+ import identity from '$stores/identity';
+ import SettingHint from '$lib/Settings/SettingHint.svelte';
+ import proxy from '$lib/Utility/proxy';
+ import { parseScheduleHtml } from '$lib/Data/hololive';
+ import type { Preferences } from '../../../graphql/$types';
+ import SvelteMarkdown from 'svelte-markdown';
+ import MarkdownLink from '$lib/MarkdownLink.svelte';
+ import LinkedTooltip from '$lib/Tooltip/LinkedTooltip.svelte';
+ import { graphql } from '$houdini';
+
+ export let data;
+
+ $: ({ Profile } = data);
+ $: preferences = $Profile.fetching ? undefined : ($Profile.data?.User.preferences as Preferences);
+
+ const setCategoriesQuery = graphql(`
+ mutation SetCategories($categories: [String!]!) {
+ setPinnedBadgeWallCategories(categories: $categories) {
+ id
+
+ preferences {
+ pinned_badge_wall_categories
+ }
+ }
+ }
+ `);
+
+ const toggleCategoryQuery = graphql(`
+ mutation ToggleCategory($category: String!) {
+ togglePinnedBadgeWallCategory(category: $category) {
+ id
+
+ preferences {
+ pinned_badge_wall_categories
+ }
+ }
+ }
+ `);
+
+ const toggleHideMissingBadgesQuery = graphql(`
+ mutation ToggleHideMissingBadges {
+ toggleHideMissingBadges {
+ id
+
+ preferences {
+ hide_missing_badges
+ }
+ }
+ }
+ `);
+
+ const toggleHideAWCBadgesQuery = graphql(`
+ mutation ToggleHideAWCBadges {
+ toggleHideAWCBadges {
+ id
+
+ preferences {
+ hide_awc_badges
+ }
+ }
+ }
+ `);
+
+ const setBiographyQuery = graphql(`
+ mutation SetBiography($biography: String!) {
+ setBiography(biography: $biography) {
+ id
+
+ preferences {
+ biography
+ }
+ }
+ }
+ `);
+
+ const setBadgeWallCSSQuery = graphql(`
+ mutation SetBadgeWallCSS($css: String!) {
+ setBadgeWallCSS(css: $css) {
+ id
+
+ preferences {
+ badge_wall_css
+ }
+ }
+ }
+ `);
+
+ $: userData = data.userData;
+
+ let error = false;
+ let schedule: ParseResult | undefined = undefined;
+ let draggedCategory: string | null = null;
+ let draggedOverCategory: string | null = null;
+
+ $: displayBadges = (username: string, badges: number | string) =>
+ $locale({
+ values: {
+ badges: badges,
+ username
+ }
+ }).user.profile.badges;
+
+ const handleDragStart = (
+ event: DragEvent & { currentTarget: EventTarget & HTMLDivElement },
+ category: string | null
+ ) => {
+ draggedCategory = category;
+
+ if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move';
+ };
+
+ const handleDragOver = (event: any) => {
+ event.preventDefault();
+
+ event.dataTransfer.dropEffect = 'move';
+ };
+
+ const handleDragEnter = (
+ event: DragEvent & { currentTarget: EventTarget & HTMLDivElement },
+ category: string | null
+ ) => {
+ event.preventDefault();
+
+ if (draggedCategory !== category && preferences && draggedCategory) {
+ draggedOverCategory = category;
+
+ const categories = preferences.pinned_badge_wall_categories;
+ const draggedIndex = categories.indexOf(draggedCategory);
+ const targetIndex = categories.indexOf(category || '');
+
+ categories.splice(draggedIndex, 1);
+ categories.splice(targetIndex, 0, draggedCategory);
+
+ preferences.pinned_badge_wall_categories = categories;
+ }
+ };
+
+ const handleDragLeave = (
+ event: DragEvent & { currentTarget: EventTarget & HTMLDivElement },
+ category: string
+ ) => {
+ event.preventDefault();
+
+ if (draggedOverCategory === category && preferences && draggedCategory) {
+ draggedOverCategory = null;
+
+ const categories = preferences.pinned_badge_wall_categories;
+ const draggedIndex = categories.indexOf(draggedCategory);
+
+ categories.splice(draggedIndex, 1);
+ categories.splice(categories.indexOf(category) + 1, 0, draggedCategory);
+
+ preferences.pinned_badge_wall_categories = categories;
+ }
+ };
+
+ const handleDrop = (event: { preventDefault: () => void }) => {
+ event.preventDefault();
+
+ if (userData && preferences)
+ setCategoriesQuery
+ .mutate({
+ categories: preferences.pinned_badge_wall_categories
+ })
+ .then();
+
+ draggedCategory = null;
+ draggedOverCategory = null;
+ };
+
+ onMount(async () => {
+ schedule = typeSchedule(
+ parseScheduleHtml(
+ await (
+ await fetch(proxy('https://schedule.hololive.tv'), {
+ headers: {
+ Cookie: 'timezone=Asia/Tokyo'
+ }
+ })
+ ).text()
+ )
+ );
+ });
+
+ const getBadgeWallCSS = () =>
+ (document.getElementById('badgeWallCSS') as HTMLTextAreaElement).value;
+
+ const getBiography = () =>
+ (document.getElementById('biography') as HTMLTextAreaElement).value.slice(0, 3000);
+
+ const toggleCategory = () => {
+ if (!userData) return;
+
+ const categoryElement = document.getElementById('category') as HTMLInputElement;
+ const category = categoryElement.value;
+
+ toggleCategoryQuery.mutate({ category }).then();
+
+ categoryElement.value = '';
+ };
- // 8.5827814569536423841e0
+ // 8.5827814569536423841e0
</script>
<HeadTitle route={`${data.username}'s Profile`} path={`/user/${data.username}`} />
{#if error}
- <AnimeRateLimited>
- <a href={`https://anilist.co/user/${data.username}`} target="_blank">@{data.username}</a>'s
- profile could not be loaded.
- </AnimeRateLimited>
+ <AnimeRateLimited>
+ <a href={`https://anilist.co/user/${data.username}`} target="_blank">@{data.username}</a>'s
+ profile could not be loaded.
+ </AnimeRateLimited>
{:else}
- {#if userData === null}
- <Message slot withReload>
- <p>
- Could not load user profile for <a
- href={`https://anilist.co/user/${data.username}`}
- target="_blank">@{data.username}</a
- >.
- </p>
- </Message>
- {:else if userData === undefined}
- <Skeleton card={false} bigCard count={1} height="224px" />
-
- <Message message="Loading user profile ..." />
- {:else}
- <div class="card card-small">
- <div
- class="card user-grid"
- style={`background-image: ${
- userData ? `url(${userData.bannerImage})` : 'none'
- }; padding: 0;`}
- >
- {#if userData}
- <img src={userData.bannerImage} alt="" class="cover-image" />
- {/if}
-
- <div class="card user-grid-content">
- <div class="user-grid-avatar">
- <LinkedTooltip content={`${userData.name}`} id="avatar" pin="avatar" relative>
- <a href={`https://anilist.co/user/${userData.name}`} target="_blank">
- <ParallaxImage
- source={$settings.displayDataSaver
- ? userData.avatar.medium
- : userData.avatar.large}
- alternativeText=""
- style="border-radius: 8px; width: 6.5em;"
- />
- </a>
- </LinkedTooltip>
- </div>
-
- <div class="user-grid-rest">
- <p>
- <a
- href={`https://anilist.co/user/${userData.name}`}
- target="_blank"
- title={String(userData.id)}
- use:tooltip
- >
- @{userData.name}
- </a>
- {#if userData && authorisedUsers.includes(userData.id)}
- &#8204;
- <button class="unclickable-button button-badge badge-rainbow">Owner</button>
- {/if}
- <span class="click-item separator opaque">•</span>
- <a href={root(`/user/${userData.name}/badges`)}>Badge Wall</a>
- </p>
-
- {#if preferences && preferences.biography && preferences.biography.length > 0}
- <SvelteMarkdown
- source={preferences.biography}
- renderers={{
- link: MarkdownLink
- }}
- />
- {/if}
-
- {$locale({
- values: {
- username: userData.name,
- anime: (userData.statistics.anime.minutesWatched / 60 / 24).toFixed(1),
- manga: estimatedDayReading(userData.statistics.manga.chaptersRead).toFixed(1)
- }
- }).user.profile.statistics}
-
- {#if schedule && preferences && preferences.biography && preferences.biography.length > 0}
- <br />
- {:else}
- <p />
- {/if}
-
- {#if $Profile.fetching}
- {displayBadges(userData.name, '...')}
- {:else if $Profile.data && $Profile.data.User}
- {@const badges = $Profile.data.User.badgesCount}
-
- {#if badges}
- {displayBadges(userData.name, badges)}
- {:else}
- {displayBadges(userData.name, '?')}
- {/if}
- {:else}
- {displayBadges(userData.name, '?')}
- {/if}
- </div>
- </div>
- </div>
- </div>
- {/if}
-
- {#if schedule && preferences && preferences.pinned_hololive_streams.length > 0}
- <p />
-
- <div class="card">
- <div class="hololive-badges">
- {#each preferences.pinned_hololive_streams as stream, index}
- {@const avatar = schedule.dict[stream]}
-
- {#if avatar}
- <LinkedTooltip
- content={stream}
- id={`hololive-badge-${index}`}
- pin={`hololive-badge-${index}`}
- relative
- >
- <a href={root(`/hololive/${encodeURIComponent(stream)}`)}>
- <div class="user-grid-hololive-badges">
- <ParallaxImage source={avatar} alternativeText="Avatar" />
- </div>
- </a>
- </LinkedTooltip>
- {/if}
- {/each}
- </div>
- </div>
- {/if}
-
- {#if preferences && userData && userData.id === $identity.id}
- <p />
-
- <details open>
- <summary>{$locale().user.preferences.title}</summary>
-
- <input
- type="checkbox"
- on:change={() => {
- if (userData) toggleHideMissingBadgesQuery.mutate(null).then();
- }}
- checked={preferences.hide_missing_badges}
- />
- {$locale().user.preferences.hideMissingBadges.title}
- <SettingHint lineBreak>{$locale().user.preferences.hideMissingBadges.hint}</SettingHint>
-
- <p />
-
- <input
- type="checkbox"
- on:change={() => {
- if (userData) toggleHideAWCBadgesQuery.mutate(null).then();
- }}
- checked={preferences.hide_awc_badges}
- />
- {$locale().user.preferences.hideAWCBadges.title}
-
- <p />
-
- Pinned Categories
-
- <div class="pinned-categories">
- {#each preferences.pinned_badge_wall_categories as category}
- <div
- class="card card-small pinned-category"
- draggable="true"
- on:dragstart={(event) => handleDragStart(event, category)}
- on:dragover={handleDragOver}
- on:dragenter={(event) => handleDragEnter(event, category)}
- on:dragleave={(event) => handleDragLeave(event, category)}
- on:drop={handleDrop}
- role="button"
- tabindex="0"
- >
- <span class="pinned-category-name">
- {category}
- </span>
-
- <button
- on:click={() => {
- if (userData) toggleCategoryQuery.mutate({ category }).then();
- }}>Remove</button
- >
- </div>
- {/each}
-
- <span class="card card-small pinned-category">
- <span class="pinned-category-name">
- <input type="text" id="category" placeholder="Category" style="width: 10em;" />
- </span>
-
- <button class="button-lined" on:click={toggleCategory}>Add</button>
- </span>
- </div>
-
- <p />
-
- Biography
-
- <button
- on:click={() => {
- if (userData)
- setBiographyQuery
- .mutate({
- biography: getBiography()
- })
- .then();
- }}>Save</button
- >
- <textarea
- value={preferences.biography}
- rows="5"
- cols="100"
- id="biography"
- placeholder="Markdown supported!"
- />
-
- <p />
-
- Badge Wall Custom CSS
-
- <button
- on:click={() => {
- if (userData)
- setBadgeWallCSSQuery
- .mutate({
- css: getBadgeWallCSS()
- })
- .then();
- }}>Save</button
- >
- <textarea
- value={preferences.badge_wall_css}
- rows="10"
- cols="100"
- id="badgeWallCSS"
- placeholder="/* Use classes and IDs such as .badges, #badges, .badge, or standard elements like body and details, or anything, as long as it's valid CSS! */"
- />
- </details>
- {/if}
+ {#if userData === null}
+ <Message slot withReload>
+ <p>
+ Could not load user profile for <a
+ href={`https://anilist.co/user/${data.username}`}
+ target="_blank">@{data.username}</a
+ >.
+ </p>
+ </Message>
+ {:else if userData === undefined}
+ <Skeleton card={false} bigCard count={1} height="224px" />
+
+ <Message message="Loading user profile ..." />
+ {:else}
+ <div class="card card-small">
+ <div
+ class="card user-grid"
+ style={`background-image: ${
+ userData ? `url(${userData.bannerImage})` : 'none'
+ }; padding: 0;`}
+ >
+ {#if userData}
+ <img src={userData.bannerImage} alt="" class="cover-image" />
+ {/if}
+
+ <div class="card user-grid-content">
+ <div class="user-grid-avatar">
+ <LinkedTooltip content={`${userData.name}`} id="avatar" pin="avatar" relative>
+ <a href={`https://anilist.co/user/${userData.name}`} target="_blank">
+ <ParallaxImage
+ source={$settings.displayDataSaver
+ ? userData.avatar.medium
+ : userData.avatar.large}
+ alternativeText=""
+ style="border-radius: 8px; width: 6.5em;"
+ />
+ </a>
+ </LinkedTooltip>
+ </div>
+
+ <div class="user-grid-rest">
+ <p>
+ <a
+ href={`https://anilist.co/user/${userData.name}`}
+ target="_blank"
+ title={String(userData.id)}
+ use:tooltip
+ >
+ @{userData.name}
+ </a>
+ {#if userData && authorisedUsers.includes(userData.id)}
+ &#8204;
+ <button class="unclickable-button button-badge badge-rainbow">Owner</button>
+ {/if}
+ <span class="click-item separator opaque">•</span>
+ <a href={root(`/user/${userData.name}/badges`)}>Badge Wall</a>
+ </p>
+
+ {#if preferences && preferences.biography && preferences.biography.length > 0}
+ <SvelteMarkdown
+ source={preferences.biography}
+ renderers={{
+ link: MarkdownLink
+ }}
+ />
+ {/if}
+
+ {$locale({
+ values: {
+ username: userData.name,
+ anime: (userData.statistics.anime.minutesWatched / 60 / 24).toFixed(1),
+ manga: estimatedDayReading(userData.statistics.manga.chaptersRead).toFixed(1)
+ }
+ }).user.profile.statistics}
+
+ {#if schedule && preferences && preferences.biography && preferences.biography.length > 0}
+ <br />
+ {:else}
+ <p />
+ {/if}
+
+ {#if $Profile.fetching}
+ {displayBadges(userData.name, '...')}
+ {:else if $Profile.data && $Profile.data.User}
+ {@const badges = $Profile.data.User.badgesCount}
+
+ {#if badges}
+ {displayBadges(userData.name, badges)}
+ {:else}
+ {displayBadges(userData.name, '?')}
+ {/if}
+ {:else}
+ {displayBadges(userData.name, '?')}
+ {/if}
+ </div>
+ </div>
+ </div>
+ </div>
+ {/if}
+
+ {#if schedule && preferences && preferences.pinned_hololive_streams.length > 0}
+ <p />
+
+ <div class="card">
+ <div class="hololive-badges">
+ {#each preferences.pinned_hololive_streams as stream, index}
+ {@const avatar = schedule.dict[stream]}
+
+ {#if avatar}
+ <LinkedTooltip
+ content={stream}
+ id={`hololive-badge-${index}`}
+ pin={`hololive-badge-${index}`}
+ relative
+ >
+ <a href={root(`/hololive/${encodeURIComponent(stream)}`)}>
+ <div class="user-grid-hololive-badges">
+ <ParallaxImage source={avatar} alternativeText="Avatar" />
+ </div>
+ </a>
+ </LinkedTooltip>
+ {/if}
+ {/each}
+ </div>
+ </div>
+ {/if}
+
+ {#if preferences && userData && userData.id === $identity.id}
+ <p />
+
+ <details open>
+ <summary>{$locale().user.preferences.title}</summary>
+
+ <input
+ type="checkbox"
+ on:change={() => {
+ if (userData) toggleHideMissingBadgesQuery.mutate(null).then();
+ }}
+ checked={preferences.hide_missing_badges}
+ />
+ {$locale().user.preferences.hideMissingBadges.title}
+ <SettingHint lineBreak>{$locale().user.preferences.hideMissingBadges.hint}</SettingHint>
+
+ <p />
+
+ <input
+ type="checkbox"
+ on:change={() => {
+ if (userData) toggleHideAWCBadgesQuery.mutate(null).then();
+ }}
+ checked={preferences.hide_awc_badges}
+ />
+ {$locale().user.preferences.hideAWCBadges.title}
+
+ <p />
+
+ Pinned Categories
+
+ <div class="pinned-categories">
+ {#each preferences.pinned_badge_wall_categories as category}
+ <div
+ class="card card-small pinned-category"
+ draggable="true"
+ on:dragstart={(event) => handleDragStart(event, category)}
+ on:dragover={handleDragOver}
+ on:dragenter={(event) => handleDragEnter(event, category)}
+ on:dragleave={(event) => handleDragLeave(event, category)}
+ on:drop={handleDrop}
+ role="button"
+ tabindex="0"
+ >
+ <span class="pinned-category-name">
+ {category}
+ </span>
+
+ <button
+ on:click={() => {
+ if (userData) toggleCategoryQuery.mutate({ category }).then();
+ }}>Remove</button
+ >
+ </div>
+ {/each}
+
+ <span class="card card-small pinned-category">
+ <span class="pinned-category-name">
+ <input type="text" id="category" placeholder="Category" style="width: 10em;" />
+ </span>
+
+ <button class="button-lined" on:click={toggleCategory}>Add</button>
+ </span>
+ </div>
+
+ <p />
+
+ Biography
+
+ <button
+ on:click={() => {
+ if (userData)
+ setBiographyQuery
+ .mutate({
+ biography: getBiography()
+ })
+ .then();
+ }}>Save</button
+ >
+ <textarea
+ value={preferences.biography}
+ rows="5"
+ cols="100"
+ id="biography"
+ placeholder="Markdown supported!"
+ />
+
+ <p />
+
+ Badge Wall Custom CSS
+
+ <button
+ on:click={() => {
+ if (userData)
+ setBadgeWallCSSQuery
+ .mutate({
+ css: getBadgeWallCSS()
+ })
+ .then();
+ }}>Save</button
+ >
+ <textarea
+ value={preferences.badge_wall_css}
+ rows="10"
+ cols="100"
+ id="badgeWallCSS"
+ placeholder="/* Use classes and IDs such as .badges, #badges, .badge, or standard elements like body and details, or anything, as long as it's valid CSS! */"
+ />
+ </details>
+ {/if}
{/if}
<style lang="scss">
- .user-grid-content {
- display: flex;
- flex-wrap: wrap;
- column-gap: 1.5em;
- background-color: rgba(0, 0, 0, 0.468);
- color: #d8d8d8;
- border-top-left-radius: 0;
- border-top-right-radius: 0;
- }
-
- .user-grid-avatar {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- }
-
- .click-item {
- margin: 0 0.625rem;
- }
-
- .user-grid {
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
- }
-
- .cover-image {
- visibility: hidden;
- height: 4.5em;
- }
-
- .user-grid-hololive-badges {
- $transitionDuration: 0.45s;
- $transition: transform $transitionDuration ease, box-shadow $transitionDuration ease;
- $size: 5.25em;
-
- border-radius: 8px;
- width: $size;
- height: $size;
- object-fit: cover;
- transition: $transition;
- box-shadow: rgba(0, 0, 11, 0.1) 0px 7px 29px 0px;
- overflow: hidden;
-
- &:hover {
- z-index: 2;
- transition: $transition;
- transform: scale(1.15);
- box-shadow: 0 1.5px 9px var(--base01), 0 0 0 4px var(--base02), 0 4px 30px var(--base01);
- }
- }
-
- .hololive-badges {
- display: flex;
- gap: 1rem;
- border-radius: 8px;
- justify-content: space-around;
- flex-wrap: wrap;
- }
-
- .separator {
- color: var(--base04);
- }
-
- .user-grid-rest {
- flex: 1;
- }
-
- .pinned-categories {
- display: flex;
- flex-wrap: wrap;
- gap: 1rem;
- }
-
- .pinned-category {
- display: flex;
- align-items: center;
- }
-
- .pinned-category-name {
- margin-right: 0.5em;
- }
+ .user-grid-content {
+ display: flex;
+ flex-wrap: wrap;
+ column-gap: 1.5em;
+ background-color: rgba(0, 0, 0, 0.468);
+ color: #d8d8d8;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ }
+
+ .user-grid-avatar {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .click-item {
+ margin: 0 0.625rem;
+ }
+
+ .user-grid {
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+ }
+
+ .cover-image {
+ visibility: hidden;
+ height: 4.5em;
+ }
+
+ .user-grid-hololive-badges {
+ $transitionDuration: 0.45s;
+ $transition: transform $transitionDuration ease, box-shadow $transitionDuration ease;
+ $size: 5.25em;
+
+ border-radius: 8px;
+ width: $size;
+ height: $size;
+ object-fit: cover;
+ transition: $transition;
+ box-shadow: rgba(0, 0, 11, 0.1) 0px 7px 29px 0px;
+ overflow: hidden;
+
+ &:hover {
+ z-index: 2;
+ transition: $transition;
+ transform: scale(1.15);
+ box-shadow: 0 1.5px 9px var(--base01), 0 0 0 4px var(--base02), 0 4px 30px var(--base01);
+ }
+ }
+
+ .hololive-badges {
+ display: flex;
+ gap: 1rem;
+ border-radius: 8px;
+ justify-content: space-around;
+ flex-wrap: wrap;
+ }
+
+ .separator {
+ color: var(--base04);
+ }
+
+ .user-grid-rest {
+ flex: 1;
+ }
+
+ .pinned-categories {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+ }
+
+ .pinned-category {
+ display: flex;
+ align-items: center;
+ }
+
+ .pinned-category-name {
+ margin-right: 0.5em;
+ }
</style>